package com.cskaoyan.javse.oop3._2inner._4loacl._3notice;

/**
 * @description: 使用局部内部类的注意事项
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 首先声明: 匿名内部类和lambda表达式都是特殊的局部内部类,这个注意事项对它们依然生效
 *
 * 当你在局部内部类的成员方法中,去修改方法的局部变量时,会编译报错:
 * Variable 'a' is accessed from within inner class, needs to be final or effectively final
 * 当你在局部内部类中访问方法的局部变量时,该变量要么就直接声明final(局部常量),要么是一个实际上的final(只要不改就是事实上的常量)
 *
 * 所以在局部内部类当中访问方法的局部变量时,是不能修改它的值的,该局部变量会变成一个常量.
 *
 * 之所这么设计,首要的原因是方法中的局部变量的生命周期和对象的生命周期有冲突,完全可能出现:
 *      方法出栈局部变量销毁,但是对象仍然需要访问该局部变量的情况
 * 于是:
 *
 * 1.为了解决方法的局部变量和对象的生命周期问题,JVM在创建局部内部类对象时,当局部内部类对象访问了方法的局部变量时,会把方法的局部变量作为对象的成员变量加入到局部内部类对象当中
 * 这样就解决了生命周期的问题,这样在方法出栈后,局部内部类对象仍然可以访问到方法的局部变量
 *
 * 2.用这种方式解决生命周期问题后,会出现新的问题,一旦在局部内部类内部修改了局部变量的取值,就存在同步的问题(因为从代码上来看,修改的是局部变量的值,而不是自身的成员变量)
 *  最终java的设计者没有采用同步的方案,只是让局部变量变为一个常量,这样就不存在同步问题
 *
 *
 *  以上,方法的局部变量如果需要在局部内部类中访问,该局部变量必须声明为final或者实际上的final(不能修改)
 *
 * 在java8之前的版本如果不给局部变量直接加上final修饰会直接编译报错,在java8之后该final修饰符被隐藏在了底层
 *      程序员可以不用给局部变量加final
 *
 */
public class Demo {
}

class EnclosedClazz {

    //外围类成员方法
    public void test() {
        //定义test方法的局部变量
        int a = 10;
        //定义局部内部类
        class Inner {
            public void testInner() {
                //在局部内部类的成员方法中,访问方法的局部变量
                System.out.println(a);
                //Variable 'a' is accessed from within inner class, needs to be final or effectively final
                //a = 100;
            }
        }

    }

}
